use std::future::Future;

use aspect_core::message_queue::QueueEntry;

use super::errors::Error;

/// Describes the set of unconsumed entries in the queue from our perspective.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct QueueView {
    /// The idx of the next entry to be read.
    next_read_idx: u64,

    /// The idx of the next entry to be written.
    next_entry_idx: u64,
}

impl QueueView {
    pub fn new(next_read_idx: u64, next_entry_idx: u64) -> Self {
        Self {
            next_read_idx,
            next_entry_idx,
        }
    }

    pub fn next_read_idx(&self) -> u64 {
        self.next_read_idx
    }

    pub fn next_entry_idx(&self) -> u64 {
        self.next_entry_idx
    }
}

pub trait QueueReader {
    /// Queries our view of the queue.
    fn get_view(&self) -> Result<QueueView, Error>;

    /// Gets en entry from the queue.
    fn get_entry(&self, idx: u64) -> Result<Option<QueueEntry>, Error>;

    /// Consumes entries up to some index, leaving the provided index as the next to be read.
    fn consume_upto(&self, next_read_idx: u64) -> Result<(), Error>;
}

pub trait AsyncQueueReader {
    /// Queries our view of the queue.
    fn get_view(&self) -> impl Future<Output = Result<QueueView, Error>> + 'static;

    /// Gets en entry from the queue.
    fn get_entry(
        &self,
        idx: u64,
    ) -> impl Future<Output = Result<Option<QueueEntry>, Error>> + 'static;

    /// Consumes entries up to some index, leaving the provided index as the next to be read.
    fn consume_upto(&self, next_read_idx: u64)
        -> impl Future<Output = Result<(), Error>> + 'static;
}
